#include <ArduinoJson.h>
#include <Wire.h>
char light[9]={2,16,0,26,0,1,2,189,25};
char closes[9]={2,16,0,26,0,1,0,60,216};
char voice[9]={2,16,0,26,0,1,3,124,217};

/*
   This sample sketch demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
#define TOKEN 1  //"3OsbPZ0wi1BOH6DIT6Jy"
String hostPort = "39.105.185.205,33333";  // 111.215.222.147,18777   udp服务器的ip地址和端口号
static const uint32_t GPSBaud = 9600;

String comdata = "";
String tindex = "";
int resets = 0; //总的udp发送次数
int emptyRest = 1600; // 自行上行gps、温湿度信息的 计数器  10秒一次
int littleRest = 40; // 小频次的上行数据
int everyRest = 0; //自行上心计数器
int everyRestOk = 0; //小频次心跳计数
int wd = 0;
int sd = 0;
char buf[100];
int flags = 1;
int statusflag = 0;  //干簧管的开启状态
int statusok = 0;  //干簧管的状态计数
int closeTimeout = 5; //干簧管从上一次吸合断开后的推送数据次数，这个控制平台的次数；
#define ok PA1 //led
#define ENA PA6 //GPS led
int ledStatus = 0;  //led指示灯的状态
void setup()
{
  Serial.begin(GPSBaud);
  Serial1.begin(GPSBaud);
  Serial2.begin(GPSBaud);
  pinMode(ok,INPUT); //pinMode(ok, OUTPUT); 
  pinMode(ENA, OUTPUT);
  pinMode(PC13, OUTPUT);
  pinMode(ok, INPUT_PULLUP);
    
}

void loop()
{
  String address = emptyInfo();    
  sendgps(address);
  
}

void sendgps(String str){
  String len = "";
  String addHex = "";

    //delay(2000);
  // put your main code here, to run repeatedly:
  if(comdata == ""){
    setColor(0, 0, 0); 
    comdata = sendcmd("AT+NCONFIG?\r\n",1000);
    Serial.println("111"); 
    Serial.println(comdata); 
 
    if(comdata.indexOf("CONNECTION_REESTABLISHMENT")!=-1 || comdata.indexOf("SUPPORT_SMS,TRUE")!=-1){    
      Serial.println("222");
      comdata = ""; 
      comdata = sendcmd("AT+CGATT=1\r\n",1000);
      Serial.println("222"); 
      Serial.println(comdata);      
      comdata = ""; 
      comdata = sendcmd("AT+CGATT?\r\n",2000);
      Serial.println("333"); 
      Serial.println(comdata);
      int flag = 0;
  
      while(comdata.indexOf("+CGATT:0")!=-1){
        Serial.println("activate context profile");
        sendcmd("AT+CGATT=1\r\n",2000);
        comdata = "";
        comdata = sendcmd("AT+CGATT?\r\n",1000);
        Serial.println(comdata);
        flag++;
        if(flag > 5) break;
      }   
      String drgam = "AT+NSOCR=DGRAM,17,1234,1\r\n";
      String retd = sendcmd(drgam,1000);
      Serial.println("444"); 
      Serial.println(retd);        
      int index = retd.toInt();
      flag = 0;
      while(retd.indexOf("ERROR")!=-1){
         retd = sendcmd(drgam,1000);
         flag++;
         if(flag > 5) break;
      }
      
      if(retd.indexOf("ERROR")!=-1){
        String rese = "AT+NRB\r\n";
        String reres = sendcmd(rese,1000);
        Serial.println(reres);  
        comdata = ""; 
      }else{

        while(retd.indexOf("OK")==-1){
         retd = sendcmd(drgam,1000);
      }
          
      Serial.println("555"); 
      Serial.println(index); 
      //len = str.length();
      //addHex = str2HexStr(str);
      tindex = String(index);


      str = emptyInfo();
      len = str.length();
      addHex = str2HexStr(str);
      String cmd = "AT+NSOST="+tindex+","+hostPort+","+len+","+addHex+"\r\n";
      Serial.println(cmd); 
      String ret = sendcmd(cmd,1000);
      Serial.println(ret); 
      flag = 0;
      while(ret.indexOf("ERROR")!=-1){
         ret = sendcmd(cmd,1000);
         flag++;
         if(flag > 5) break;
      }

      if(ret.indexOf("ERROR")!=-1){
        String rese = "AT+NRB\r\n";
        String reres = sendcmd(rese,1000);
        Serial.println(reres);  
        comdata = ""; 
      }else{

          Serial.println("666"); 
        
          len = str.length();
          addHex = str2HexStr(str);
          String cmd1 = "AT+NSOST="+tindex+","+hostPort+","+len+","+addHex+"\r\n";
          Serial2.write(cmd1.c_str());
          delay(1000);
          Serial.println("555");
        }
      
        
      }  
      
 
      

    }else{
      if(comdata.indexOf("ERROR")!=-1){
        String rese = "AT+NRB\r\n";
        String reres = sendcmd(rese,1000);
        Serial.println(reres);  
      }  
      comdata = "";      
    }
  }else{
      char *revbuf[8] = {0}; //存放分割后的子字符串 
      //分割后子字符串的个数
      int num = 0;

     //if(flags == 1){
          Serial.println("AT+NSORF");
          String backcmd = "AT+NSORF="+tindex+",30\r\n";
          String backinfo = "";
          backinfo = sendcmdx(backcmd);
          strcpy(buf,backinfo.c_str());
          //Serial.println(buf);
          split(buf,",",revbuf,&num); //调用函数进行分割
          //输出返回的每个内容 
    
          Serial.println(revbuf[3]);        
          unsigned char bufs[100]={0};
          Hex2Byte(revbuf[3],bufs,strlen(revbuf[3]));
          String strxx="";
          strxx=(char*)bufs;
          //Serial.println(strxx);
          StaticJsonBuffer<200> jsonBuffer;
          JsonObject& root = jsonBuffer.parseObject(bufs);
          const char* met = root["met"];
          const char* v = root["v"];
          Serial.println(met);
          Serial.println(v);
          //Serial.println(backinfo);
          resets++;
          Serial.println(resets);
          String methods = (char*)met;
          if(methods.indexOf("open")!=-1){
            flags = 0;
            Serial.println("light"); 
            //analogWrite(ok,atoi(v));
            setColor(atoi(v), atoi(v), atoi(v));
            str = stateInfo(1);
            len = str.length();
            addHex = str2HexStr(str);
            String cmd = "AT+NSOST="+tindex+","+hostPort+","+len+","+addHex+"\r\n";
            Serial.println(str); 
            Serial2.write(cmd.c_str()); 
            delay(1000);
            flags = 1;      
            /*if(methodName == "setStatus"){
                Serial1.write(tempStr1.c_str());
            }else{
                String emptys = emptyInfo();
                Serial1.write(emptys.c_str());
            }*/     
          }
          
           if(methods.indexOf("close")!=-1){
            statusflag=1;
            flags = 0;
            Serial.println("close"); 
            //analogWrite(ok,0);
            digitalWrite(ok, HIGH);
            setColor(atoi(v), atoi(v), atoi(v));
            str = stateInfo(0);
            len = str.length();
            addHex = str2HexStr(str);
            String cmd = "AT+NSOST="+tindex+","+hostPort+","+len+","+addHex+"\r\n";
            Serial.println(str); 
            Serial2.write(cmd.c_str());          
            delay(1000);
            flags = 1;            
            /*if(methodName == "setStatus"){
                Serial1.write(tempStr1.c_str());
            }else{
                String emptys = emptyInfo();
                Serial1.write(emptys.c_str());
            }*/     
          }     
            int val = digitalRead(ok);
            Serial.print("read digital A1's value is: ");
            Serial.println(val);
            if(ledStatus==0){
              //setColor(0, 0, 0);
              digitalWrite(PC13, HIGH);
              ledStatus = 1;
            }else{
              //setColor(255, 255, 255);
              digitalWrite(PC13, LOW);
              ledStatus = 0;
            }
            if(val==0){
              closeTimeout=5;
              statusflag=1; // 干簧管吸合
              if(statusok>3){
                  statusok=0;
                  str = emptyInfo();
                  len = str.length();
                  addHex = str2HexStr(str);
                  String cmd = "AT+NSOST="+tindex+","+hostPort+","+len+","+addHex+"\r\n"; 
                  Serial.println(str); 
                  Serial2.write(cmd.c_str());                
                }
                statusok++;
            }else if(statusflag==1){
              
              if(statusok>20){
                  statusok=0;
                  closeTimeout--;
                  str = emptyInfo();
                  len = str.length();
                  addHex = str2HexStr(str);
                  String cmd = "AT+NSOST="+tindex+","+hostPort+","+len+","+addHex+"\r\n"; 
                  Serial.println(str); 
                  Serial2.write(cmd.c_str());
                  if(closeTimeout==0){ 
                    statusflag=0;
                  }                
              }
              statusok++;
            }
            if(everyRest >= emptyRest){
                str = emptyInfo();
                len = str.length();
                addHex = str2HexStr(str);
                String cmd = "AT+NSOST="+tindex+","+hostPort+","+len+","+addHex+"\r\n";
                Serial.println(str); 
                Serial2.write(cmd.c_str());
                everyRest = 0;
                //Serial1.write(&closes[0],9);
            }

            if(everyRestOk >= littleRest){
                str = emptyInfo();
                len = str.length();
                addHex = str2HexStr(str);
                String cmd = "AT+NSOST="+tindex+","+hostPort+",1,31\r\n";
                Serial.println(cmd); 
                Serial2.write(cmd.c_str());
                everyRestOk = 0;
                //Serial1.write(&closes[0],9);
            }
            everyRestOk++;
            everyRest++;
         
          
          //delay(1000);
          if(resets>2000){
            comdata = "";
            String cmd = "AT+NSOCL=0\r\n";
            String retd = sendcmd(cmd,1000);
            Serial.println(retd);
            resets = 0;
          } 
          Serial.println(resets); 
      //}
      
  }
  
}

void split(char *src,const char *separator,char **dest,int *num) {
  /*
    src 源字符串的首地址(buf的地址) 
    separator 指定的分割字符
    dest 接收子字符串的数组
    num 分割后子字符串的个数
  */
     char *pNext;
     int count = 0;
     if (src == NULL || strlen(src) == 0) //如果传入的地址为空或长度为0，直接终止 
        return;
     if (separator == NULL || strlen(separator) == 0) //如未指定分割的字符串，直接终止 
        return;
     pNext = (char *)strtok(src,separator); //必须使用(char *)进行强制类型转换(虽然不写有的编译器中不会出现指针错误)
     while(pNext != NULL) {
          *dest++ = pNext;
          ++count;
         pNext = (char *)strtok(NULL,separator);  //必须使用(char *)进行强制类型转换
    }  
    *num = count;
} 

String reset(){
   String resetComm = "AT+NRB\r\n";
   return sendcmd(resetComm,1000);  
}

char *strrpc(char *str,char *oldstr,char *newstr){
    char bstr[strlen(str)];//转换缓冲区
    memset(bstr,0,sizeof(bstr));
 
    for(int i = 0;i < strlen(str);i++){
        if(!strncmp(str+i,oldstr,strlen(oldstr))){//查找目标字符串
            strcat(bstr,newstr);
            i += strlen(oldstr) - 1;
        }else{
          strncat(bstr,str + i,1);//保存一字节进缓冲区
      }
    }
 
    strcpy(str,bstr);
    return str;
} 

String sendcmd(String cmd, int timeout){
  //Serial2.flush();
  Serial2.write(cmd.c_str());
  delay(timeout);
  comdata = "";
  while(Serial2.available() > 0){
  comdata+= char(Serial2.read());
    delay(2);
  }
  //Serial.println(comdata);
  //lcd.clear();
  //lcd.print(comdata);
  return comdata;
}

String sendcmdx(String cmd){
  //Serial2.flush();
  Serial2.write(cmd.c_str());
  delay(500);
  comdata = "";
  while(Serial2.available() > 0){
  comdata+= char(Serial2.read());
    delay(2);
  }
  //Serial.println(comdata);
  //lcd.clear();
  //lcd.print(comdata);
  return comdata;
}

String str2HexStr(String strin)
{
  int lenuse = strin.length();
  char charBuf[lenuse*2-1];
  char strBuf[lenuse*2-1];
  String strout = "";
  strin.toCharArray(charBuf,lenuse*2) ;
  for (int i = 0; i < lenuse; i++)
  {
    sprintf(strBuf, "%02X", charBuf[i]);

    if (String(strBuf) != F("00") )
    {
           strout += strBuf;
    }
  }

  return strout;
}

void Hex2Byte(const char* source, unsigned char* dest, int sourceLen)
{
    short i;
    unsigned char highByte, lowByte;
    for (i = 0; i < sourceLen; i += 2)
    {
        highByte = toupper(source[i]);
        lowByte  = toupper(source[i + 1]);
        if (highByte > 0x39)  
            highByte -= 0x37; //'A'->10 'F'->15
        else
            highByte -= 0x30; //'1'->1 '9'->9
        if (lowByte > 0x39)
            lowByte -= 0x37;
        else
            lowByte -= 0x30;
        dest[i / 2] = (highByte << 4) | lowByte;
    }
}

String emptyInfo(){
  StaticJsonBuffer<700> jsonBuffer;
  JsonObject& data = jsonBuffer.createObject();
  data["token"] = TOKEN;
  data["index"] = 0;
  data["lock"] = digitalRead(ok);
  char payload[256];
  data.printTo(payload, sizeof(payload));
  String strPayload = String(payload);  
  return strPayload;  
}

String stateInfo(int state){
  StaticJsonBuffer<700> jsonBuffer;
  JsonObject& data = jsonBuffer.createObject();
  data["token"] = TOKEN;
  data["state"] = state;
  char payload[256];
  data.printTo(payload, sizeof(payload));
  String strPayload = String(payload);  
  return strPayload;  
}


void setColor(int red, int green, int blue)
{
  analogWrite(ENA, 255-red);
  analogWrite(ENA, 255-green);
  analogWrite(ENA, 255-blue);  
}
